package com.atguigu.tingshu.payment.service.impl;

import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.model.payment.PaymentInfo;
import com.atguigu.tingshu.payment.config.WxPayV3Config;
import com.atguigu.tingshu.payment.service.PaymentInfoService;
import com.atguigu.tingshu.payment.service.WxPayService;
import com.atguigu.tingshu.payment.util.PayUtil;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

    @Autowired
    private PaymentInfoService paymentInfoService;

    @Autowired
    private RSAAutoCertificateConfig config;

    @Autowired
    private WxPayV3Config wxPayV3Config;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 获取小程序拉起微信支付所需参数
     *
     * @param paymentType 支付类型 1301-订单 1302-充值
     * @param orderNo     交易订单号或充值订单号
     * @return {"timeStamp":"","package":"","paySign":"","signType":"RSA","nonceStr":""}
     */
    @Override
    public Map<String, String> createJsapi(Long userId, String paymentType, String orderNo) {
        //1.保存封装本地交易记录
        PaymentInfo paymentInfo = paymentInfoService.savePaymentInfo(paymentType, orderNo);
        //支付状态：1401-未支付 1402-已支付
        String paymentStatus = paymentInfo.getPaymentStatus();
        //判断本地交易支付状态
        if (SystemConstant.PAYMENT_STATUS_PAID.equals(paymentStatus)) {
            throw new GuiguException(500, "当前交易已支付");
        }

        //2.TODO 对接微信支付接口获取小程序拉起微信支付相关参数
        //2.1 构建支付service对象
        JsapiServiceExtension service =
                new JsapiServiceExtension.Builder().config(config).build();

        //2.2 创建预支付请求对象 用于产生微信交易
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        //TODO 开发中将应付金额设置为1分
        amount.setTotal(1);
        //amount.setTotal(paymentInfo.getAmount());
        request.setAmount(amount);
        request.setAppid(wxPayV3Config.getAppid());
        request.setMchid(wxPayV3Config.getMerchantId());
        request.setDescription(paymentInfo.getContent());
        request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
        request.setOutTradeNo(paymentInfo.getOrderNo());
        //TODO 小程序还未上线，只允许应用下开发者用户付款 设置付款者唯一标识
        Payer payer = new Payer();
        payer.setOpenid("odo3j4qp-wC3HVq9Z_D9C0cOr0Zs");
        request.setPayer(payer);
        //2.3 调用下单方法，得到响应，封装调起支付的参数
        PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
        if (response != null) {
            String timeStamp = response.getTimeStamp();
            String nonceStr = response.getNonceStr();
            String packageVal = response.getPackageVal();
            String signType = response.getSignType();
            String paySign = response.getPaySign();
            Map<String, String> map = new HashMap<>();
            map.put("timeStamp", timeStamp);
            map.put("nonceStr", nonceStr);
            map.put("package", packageVal);
            map.put("signType", signType);
            map.put("paySign", paySign);
            return map;
        }
        return null;
    }

    /**
     * 查询订单交易状态
     *
     * @param orderNo
     * @return
     */
    @Override
    public boolean queryPayStatus(String orderNo) {
       /* //1.构建支付service对象
        JsapiServiceExtension service =
                new JsapiServiceExtension.Builder().config(config).build();
        //2.根据商户侧订单编号查询交易
        QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
        request.setMchid(wxPayV3Config.getMerchantId());
        request.setOutTradeNo(orderNo);
        Transaction transaction = service.queryOrderByOutTradeNo(request);
        //3.判断交易状态
        if (transaction != null) {
            log.info("订单对应交易结果:{}" + transaction);
            Transaction.TradeStateEnum tradeState = transaction.getTradeState();
            if (Transaction.TradeStateEnum.SUCCESS == tradeState) {
                return true;
            }
        }
        return false;*/

        //1.模拟创建微信交易对象
        Transaction transaction = new Transaction();
        transaction.setTransactionId("wx"+ IdUtil.getSnowflakeNextId());
        transaction.setOutTradeNo(orderNo);
        //2.调用本地交易记录业务方法处理核心业务
        paymentInfoService.updatePaymentInfo(transaction);
        return true;
    }

    /**
     * 用户付款成功后，微信支付回调接口
     *
     * @param request
     * @return {code:"SUCCESS",message:"支付成功"}
     */
    @Override
    public Map<String, String> notifyPayResult(HttpServletRequest request) {
        //1.验签及获取请求体业务数据 防止出现虚假通知
        //1.1 获取HTTP请求头中会包含报文的签名信息，用于验签
        String signature = request.getHeader("Wechatpay-Signature");
        String serial = request.getHeader("Wechatpay-Serial");
        String nonce = request.getHeader("Wechatpay-Nonce");
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        String signaureType = request.getHeader("Wechatpay-Signature-Type");
        log.info("[支付服务]签名：{}，序列号：{}，随机数：{}，时间戳：{}，签名类型：{}", signature, serial, nonce, timestamp, signaureType);

        //1.2 创建请求参数对象：封装微信提交请求体参数（密文）
        String body = PayUtil.readData(request);
        log.info("[支付服务]微信请求体参数：{}", body);
        RequestParam requestParam =
                new RequestParam.Builder()
                        .serialNumber(serial)
                        .nonce(nonce)
                        .signature(signature)
                        .timestamp(timestamp)
                        .body(body)
                        .build();

        //1.2 基于签名信息进行验签，验签通过后获取请求体业务数据
        NotificationParser parser = new NotificationParser(config);
        Transaction transaction = parser.parse(requestParam, Transaction.class);

        //2.幂等性处理
        if (transaction != null) {
            //2.1 获取本次通知唯一标识：使用微信订单交易号、商户订单编号等
            String outTradeNo = transaction.getOutTradeNo();
            //2.2 构建RedisKey采用set ex nx 存入Redis
            String redisKey = "pay:weixin:notify:" + outTradeNo;
            Boolean flag = redisTemplate.opsForValue().setIfAbsent(redisKey, outTradeNo, 25, TimeUnit.HOURS);
            if (flag) {
                //3.业务校验：验证 支付状态（支付成功）、金额（用户实付金额跟应付金额是否一致）
                Transaction.TradeStateEnum tradeState = transaction.getTradeState();
                //3.1 验证付款状态
                if (Transaction.TradeStateEnum.SUCCESS == tradeState) {
                    //3.2 验证金额
                    Integer payerTotal = transaction.getAmount().getPayerTotal();
                    if (payerTotal.intValue() == 1) {
                        //4.TODO 核心业务：更新本地交易记录（状态，微信支付订单号、回调信息）
                        paymentInfoService.updatePaymentInfo(transaction);
                        //5.响应微信支付系统：SUCCESS
                        Map<String, String> map = new HashMap<>();
                        map.put("code", "SUCCESS");
                        map.put("message", "成功");
                        return map;
                    }
                    try {
                    } catch (Exception e) {
                        redisTemplate.delete(redisKey);
                        throw new RuntimeException(e);
                    }
                }
            }
        }


        return null;
    }

    /**
     * 退款
     *
     * @param orderNo
     */
    @Override
    public Refund refunds(String orderNo) {
        RefundService service =
                new RefundService.Builder().config(config).build();
        CreateRequest request = new CreateRequest();
        //TODO 查询退款结果
        //service.queryByOutRefundNo()
        //TODO 远程调用获取订单信息
        AmountReq amountReq = new AmountReq();
        amountReq.setTotal(1L);
        amountReq.setRefund(1L);
        amountReq.setCurrency("CNY");
        request.setAmount(amountReq);
        request.setOutTradeNo(orderNo);
        request.setReason("用户申请退款:" + orderNo);
        //request.setSubMchid(wxPayV3Config.getMerchantId());
        request.setOutRefundNo("dk"+orderNo);
        Refund refund = service.create(request);
        if (refund != null) {
            log.info("[支付服务]退款响应结果：{}", refund);
            return refund;
        }
        return null;
    }


    /**
     * 关闭微信支付订单
     *
     * @param orderNo
     * @return
     */
    @Override
    public void closeWxPay(String orderNo) {
        //1.构建支付service对象
        JsapiServiceExtension service =
                new JsapiServiceExtension.Builder().config(config).build();
        //2.根据商户侧订单编号关闭交易
        CloseOrderRequest request = new CloseOrderRequest();
        request.setMchid(wxPayV3Config.getMerchantId());
        request.setOutTradeNo(orderNo);
        service.closeOrder(request);
    }
}
